package com.imddy.spbatch001.utils;

import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class ListFindUtils {
    private static final Logger log = LoggerFactory.getLogger(ListFindUtils.class);

    // 缓存反射得到的方法和字段，以提高性能
    private static final ThreadLocal<Map<Class<?>, Map<String, Method>>> methodCache = ThreadLocal.withInitial(HashMap::new);
    private static final ThreadLocal<Map<Class<?>, Map<String, Field>>> fieldCache = ThreadLocal.withInitial(HashMap::new);

    /**
     * 根据方法名查找对象，并返回匹配对象的另一属性值。
     */
    public static <T, R> R findObjectByMethod(Object targetObjectValue, String getterMethodName, String returnGetterMethodName, List<T> objectList, Class<T> tClass) {
        Method getterMethod = getMethod(tClass, getterMethodName);
        Method returnGetterMethod = getMethod(tClass, returnGetterMethodName);
        if (getterMethod == null || returnGetterMethod == null) {
            log.error("Methods not found.");
            return null;
        }

        try {
            for (T t : objectList) {
                Object object1 = getterMethod.invoke(t);
                if (Objects.equals(targetObjectValue, object1)) {
                    return (R) returnGetterMethod.invoke(t);
                }
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            log.error("Error invoking methods.", e);
        }
        return null;
    }

    /**
     * 通过字段查找对象，并返回匹配对象的另一字段值。
     */
    public static <T, R> R findObjectByField(Object targetObjectValue, String fieldName, String returnFieldName, List<T> objectList, Class<T> tClass) {
        Field field = getField(tClass, fieldName);
        Field returnField = getField(tClass, returnFieldName);
        if (field == null || returnField == null) {
            log.error("Fields not found.");
            return null;
        }

        try {
            for (T t : objectList) {
                field.setAccessible(true);
                Object object1 = field.get(t);
                if (Objects.equals(targetObjectValue, object1)) {
                    returnField.setAccessible(true);
                    return (R) returnField.get(t);
                }
            }
        } catch (IllegalAccessException e) {
            log.error("Error accessing fields.", e);
        }
        return null;
    }

    /**
     * 根据方法名查找对象并返回。
     */
    public static <T> T findByMethod(Object targetObjectValue, String methodName, List<T> objectList, Class<T> tClass) {
        Method method = getMethod(tClass, methodName);
        if (method == null) {
            log.error("Method not found.");
            return null;
        }

        try {
            for (T t : objectList) {
                Object value = method.invoke(t);
                if (Objects.equals(value, targetObjectValue)) {
                    return t;
                }
            }
        } catch (IllegalAccessException | InvocationTargetException e) {
            log.error("Error invoking method.", e);
        }
        return null;
    }

    /**
     * 通过字段查找对象并返回。
     */
    public static <T> T findByField(Object targetObjectValue, String fieldName, List<T> objectList, Class<T> tClass) {
        Field field = getField(tClass, fieldName);
        if (field == null) {
            log.error("Field not found.");
            return null;
        }

        try {
            for (T t : objectList) {
                field.setAccessible(true);
                Object value = field.get(t);
                if (Objects.equals(value, targetObjectValue)) {
                    return t;
                }
            }
        } catch (IllegalAccessException e) {
            log.error("Error accessing field.", e);
        }
        return null;
    }

    private static Method getMethod(Class<?> clazz, String methodName) {
        Map<String, Method> cache = methodCache.get().computeIfAbsent(clazz, k -> new HashMap<>());
        return cache.computeIfAbsent(methodName, name -> {
            try {
                return clazz.getMethod(name);
            } catch (NoSuchMethodException e) {
                log.error("Method {} not found in class {}", name, clazz.getName());
                return null;
            }
        });
    }

    private static Field getField(Class<?> clazz, String fieldName) {
        Map<String, Field> cache = fieldCache.get().computeIfAbsent(clazz, k -> new HashMap<>());
        return cache.computeIfAbsent(fieldName, name -> {
            try {
                return clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                log.error("Field {} not found in class {}", name, clazz.getName());
                return null;
            }
        });
    }








    public void test001() throws NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        List<TtVo> ttVoList = new ArrayList<>();
        TtVo ttVo1 = new TtVo();
        ttVo1.setId(1);
        ttVo1.setPai("first Name");
        ttVoList.add(ttVo1);
        TtVo ttVo2 = new TtVo();
        ttVo2.setId(2);
        ttVo2.setPai("Name Second");
        ttVoList.add(ttVo2);
        TtVo ttVo3 = new TtVo();
        ttVo3.setId(3);
        ttVo3.setPai("张三");
        ttVoList.add(ttVo3);
        TtVo ttVo4 = new TtVo();
        ttVo4.setId(4);
        ttVo4.setPai("麻四");
        ttVoList.add(ttVo4);
        TtVo ttVo5 = new TtVo();
        ttVo5.setId(5);
        ttVo5.setPai("five Name");
        ttVoList.add(ttVo5);

        TtVo ttVo301 = new TtVo();
        ttVo301.setId(301);
        ttVo301.setPai("three thrad one! ");
        ttVoList.add(ttVo301);
        TtVo ttVo302 = new TtVo();
        ttVo302.setId(302);
        ttVo302.setPai("three 302 xxx! ");
        ttVoList.add(ttVo302);
        TtVo ttVo303 = new TtVo();
        ttVo303.setId(303);
        ttVo303.setPai("five303Name");
        ttVoList.add(ttVo303);




        Object s1 = ListFindUtils.findObjectByMethod("five Name", "getPai", "getId", ttVoList, TtVo.class);
        log.info("s1: " + s1 );
        Object s2 = ListFindUtils.findObjectByMethod(3, "getId", "getPai", ttVoList, TtVo.class);
        log.info("s2: " + s2 );
        Object s3 = ListFindUtils.findObjectByMethod("麻四", "getPai", "getId", ttVoList, TtVo.class);
        log.info("s3: " + s3 );


        Object s4 = ListFindUtils.findObjectByField("five Name", "pai", "id", ttVoList, TtVo.class);
        log.info("s4: " + s4 );
        Object s5 = ListFindUtils.findObjectByField(3, "id", "pai", ttVoList, TtVo.class);
        log.info("s5: " + s5 );
        Object s6 = ListFindUtils.findObjectByField("麻四", "pai", "id", ttVoList, TtVo.class);
        log.info("s6: " + s6 );



        Object s7 = ListFindUtils.findByMethod(1, "getId", ttVoList, TtVo.class);
        log.info("s7: " + s7 );
        Object s8 = ListFindUtils.findByMethod(5, "getId", ttVoList, TtVo.class);
        log.info("s8: " + s8 );
        Object s9 = ListFindUtils.findByMethod("张三", "getPai", ttVoList, TtVo.class);
        log.info("s9: " + s9 );
        Object s10 = ListFindUtils.findByMethod("麻四", "getPai", ttVoList, TtVo.class);
        log.info("s10: " + s10 );

        Object s11 = ListFindUtils.findByField(1, "id", ttVoList, TtVo.class);
        log.info("s11: " + s11 );
        Object s12 = ListFindUtils.findByField(5, "id", ttVoList, TtVo.class);
        log.info("s12: " + s12 );
        Object s13 = ListFindUtils.findByField("张三", "pai", ttVoList, TtVo.class);
        log.info("s13: " + s13 );
        Object s14 = ListFindUtils.findByField("麻四", "pai", ttVoList, TtVo.class);
        log.info("s14: " + s14 );

        log.info("-------------------------------------------------------------------------------------");
        Object s21 = ListFindUtils.findObjectByMethod("five303Name", "getPai", "getId", ttVoList, TtVo.class);
        log.info("s21: " + s21 );
        Object s22 = ListFindUtils.findObjectByMethod(303, "getId", "getPai", ttVoList, TtVo.class);
        log.info("s22: " + s22 );
        Object s23 = ListFindUtils.findObjectByMethod("three 302 xxx! ", "getPai", "getId", ttVoList, TtVo.class);
        log.info("s23: " + s23 );

        Object s24 = ListFindUtils.findObjectByField("five303Name", "pai", "id", ttVoList, TtVo.class);
        log.info("s24: " + s24 );
        Object s25 = ListFindUtils.findObjectByField(303, "id", "pai", ttVoList, TtVo.class);
        log.info("s25: " + s25 );
        Object s26 = ListFindUtils.findObjectByField("three 302 xxx! ", "pai", "id", ttVoList, TtVo.class);
        log.info("s26: " + s26 );



        Object s27 = ListFindUtils.findByMethod(303, "getId", ttVoList, TtVo.class);
        log.info("s27: " + s27 );
        Object s28 = ListFindUtils.findByMethod(301, "getId", ttVoList, TtVo.class);
        log.info("s28: " + s28 );
        Object s29 = ListFindUtils.findByMethod("张三", "getPai", ttVoList, TtVo.class);
        log.info("s29: " + s29 );
        Object s30 = ListFindUtils.findByMethod("three 302 xxx! ", "getPai", ttVoList, TtVo.class);
        log.info("s30: " + s30 );

        Object s31 = ListFindUtils.findByField(303, "id", ttVoList, TtVo.class);
        log.info("s31: " + s31 );
        Object s32 = ListFindUtils.findByField(301, "id", ttVoList, TtVo.class);
        log.info("s32: " + s32 );
        Object s33 = ListFindUtils.findByField("张三", "pai", ttVoList, TtVo.class);
        log.info("s33: " + s33 );
        Object s34 = ListFindUtils.findByField("three 302 xxx! ", "pai", ttVoList, TtVo.class);
        log.info("s34: " + s34 );

    }

    @Data
    class TtVo {
        private Integer id;
        private String pai;
    }


    public static void main(String[] args) throws NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        new ListFindUtils().test001();
    }

}
